Conceitos de Docker

Tempo estimado de leitura: 6min

Dockerfile

O Dockerfile provê instruções de como se construir a imagem de um container (usando o comando docker build -t <nome_dessa_img> <caminho_do_dockerfile>). Começa a partir de alguma imagem Base (usando o comando FROM), seguido de quaisquer outras instruçoes necessárias

Então, a gente "compila" esse código, tendo como resultado uma imagem que poderemos interagir com.

principais comandos

Comando Descrição Uso
ARG Define uma variavel que o usuário pode passar ao buildar a imagem (usando a flag --build-arg

essa variável só fica disponivel nas etapas de build da imagem (ou seja, só no dockerfile, mas nao no container)

nao use isso pra passar 'segredos' já que os valores podem ser acessados usando docker history

ˢᶦⁿᵗᵃˣᵉ ↴

ARG <name>[=<default value>]

ᵉˣᵉᵐᵖˡᵒ ↴

ARG version
ARG user_name=admin

como se usaria:

$ docker build --build-arg version=1.0 -t <nome_img> .

$ docker build --build-arg version=1.1 \
               --build-arg user_name=joao \
               -t <nome_img> .
ENV Define uma variavel de ambiente que será utilizada tanto em build-time como em run-time (ou seja, os containers em execução também possuem essa ENV definida). O usuário pode passar o valor utilizando a flag --env ou -e

nao use ENV caso so precise do valor em build-time

ˢᶦⁿᵗᵃˣᵉ ↴

ENV <key>=<value> ...
ENV <key> <value> # com essa sintaxe, apenas um por linha

ᵉˣᵉᵐᵖˡᵒ ↴

ENV NODE_ENV="development"

ENV POSTGRES_USER="username" \
    POSTGRES_PASSWORD="password" \

ARG build_value
ENV run_value=$build_value

como se usaria:

# cenario 1
$ docker run --env NODE_ENV=production <nome_img>


# cenario 2
$ docker build --build-arg build_value=5 -t <nome_img> .

$ docker run -e run_value=8 <nome_img>
FROM especifica a imagem base que será utilizada

primeiro busca-se essa imagem localmente, caso nao encontre, busca-se no dockerhub o repositorio mais adequado

ˢᶦⁿᵗᵃˣᵉ ↴

FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]

ᵉˣᵉᵐᵖˡᵒˢ ↴

padrão
FROM node:14-alpine

usando imagem de outro registry (ECR da AWS)
FROM public.ecr.aws/micahhausler/alpine:3.14.0

recebendo plataformas da cli como ARG
ARG architecture
FROM --platform=linux/${architecture} openjdk
LABEL adiciona metadados a imagem.
é feito através de pares de key-value (criados por você mesmo)

isso pode ser, então, verificado com o comando docker inspect

ˢᶦⁿᵗᵃˣᵉ ↴

LABEL <key>=<value> <key>=<value> <key>=<value> ...

ᵉˣᵉᵐᵖˡᵒ ↴

LABEL aleatorio.nome="valor1"
LABEL aleatorio.data="valor2"
LABEL chave1="c1" chave2="c2" \
      chave3="c3"
WORKDIR define qual será o diretorio de trabalho em build-time (o caminho relativo de qualquer comando RUN, CMD, ENTRYPOINT, COPY e ADD será esse diretório);

caso o diretório não exista, este será criado

caso passe um caminho relativo (não-absoluto), este será usado em relação ao ultimo WORKDIR definido

ˢᶦⁿᵗᵃˣᵉ ↴

WORKDIR /path/to/workdir

ᵉˣᵉᵐᵖˡᵒ ↴

WORKDIR /pasta1
WORKDIR /pasta2
WORKDIR pasta3

o resultado seria:

.
├── pasta1
└── pasta2
         └── pasta3 <diretorio atual>

USER configura qual será o usuário (opcionalmente o grupo, também [caso não especifique, será root]) que será utilizado dali em diante (tanto em build-time como run-time)

o usuário tem que ser criado por você previamente no dockerfile

ˢᶦⁿᵗᵃˣᵉ ↴

USER <user>[:<group>]

ᵉˣᵉᵐᵖˡᵒ ↴

RUN groupadd -r grupo \
 && useradd usuario --groups grupo

USER usuario
USER usuario:grupo
COPY

copia arquivos/diretorios do Host (em relação ao contexto da build) para o Container (em relação ao WORKDIR)


pode-se utilizar wildcards nos caminhos advindos do host:

  • * da match em qualquer sequencia de chars que não sejam separador (/, ou \ no windows)
  • ? o mesmo, mas pra 1 char só

--chown não funciona no windows
não é mt recomendado o uso disso, já que o usuario só precisa de permissão pra executar, e não o ~domínio/ownership

para efeito de comparação/entendimento:


ˢᶦⁿᵗᵃˣᵉ ↴

COPY [--chown=<user>:<group>] <caminho_no_seu_pc>... <destino_no_container>
COPY [--chown=<user>:<group>] ["<caminho_no_seu_pc>",... "<destino_no_container>"]

A versão com [] é utilizada qnd se tem whitespace no path (ex: '/home/joao/minha pasta/')

ᵉˣᵉᵐᵖˡᵒ ↴

COPY minha_pasta/ /tmp/my_folder
COPY ["package*.json", "yarn.lock", "/meu_app/"]
COPY . .
ADD

O mesmo que o COPY, mas:

  1. a fonte pode ser uma URL também (não recomendado, melhor usar RUN curl ou RUN wget etc)
  2. auto-extrai arquivos .tar

Mais sobre as diferenças aqui.

ˢᶦⁿᵗᵃˣᵉ ↴

ADD [--chown=<user>:<group>] <src>... <dest>
ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]

ᵉˣᵉᵐᵖˡᵒ ↴

ADD hom* /mydir/
ADD rootfs.tar.xz /
ADD https://example.com/music.mp3 /usr/src/things/
CMD

Provê algum padrão pro container em execução

só pode um CMD por dockerfile (caso tenham multiplos apenas o ultimo é considerado)

o formato exec não invoca um shell (a nao ser que especifique [ex: CMD ["sh", "-c", "echo $HOME"] ])

justamente por isso, CMD [ "echo", "$HOME" ] não teria o resultado esperado já que não há um shell pra processar/substituir a variavel

ˢᶦⁿᵗᵃˣᵉ ↴

# exec
CMD ["executable","param1","param2"]

# parametros pro ENTRYPOINT
CMD ["param1","param2"]

# shell
CMD command param1 param2

ᵉˣᵉᵐᵖˡᵒ ↴

CMD echo "This is a test."
CMD ["npm", "start"]
ENTRYPOINT

permite configurar um container pra ser rodado como um executavel

ˢᶦⁿᵗᵃˣᵉ ↴

# exec
ENTRYPOINT ["executable", "param1", "param2"]

# shell
ENTRYPOINT command param1 param2

ᵉˣᵉᵐᵖˡᵒ ↴

# exec
ENTRYPOINT ["top", "-b"]
CMD ["-c"]

# shell
ENTRYPOINT exec top -b

BuildKit - Segredos

No Windows/Mac, BuildKit já é utilizado por padrão; no Linux, não. Para saber como ativar, leia aqui

Caso queira, o comando abaixo verifica se o arquivo de configurações personalizadas já existe e, caso nao exista, cria o mesmo já especificando o uso do Buildkit:

$ test -f /etc/docker/daemon.json || (echo '{ "features": { "buildkit": true } }' |  sudo tee /etc/docker/daemon.json)

~~ dar exemplo com segredo do Github, JWT ou bCrypt etc

otimizando build

docker layered cache

torre de hanoi

Only the instructions RUN, COPY, ADD create layers. Other instructions create temporary intermediate images, and do not increase the size of the build.

Docker cacheia as instruções no Dockerfile por camadas. Fazendo um paralelo com a Torre de Hanoi: pense que o Dockerfile é a torre (de cabeça pra baixo); entao, sempre que ouver alteração em alguma linha/camada, todas as peças que estão em cima são descartadas.

Por isso é tão frequente ver a seguinte estrutura em um projeto JS:

Correto Incorreto
COPY package*.json .

RUN npm install

COPY . .
COPY . .

RUN npm install

Já que o comando COPY . . copia todos os arquivos, e o código-fonte está em constante alteração, isso significa que toda vez que fosse buildar essa imagem, haver-se-ia de descartar o comando seguinte (npm install), resultando na re-execução desse comando.

comando onbuild

multistage build

dockerignore

volumes

docker pull

registry x repositories

https://stackoverflow.com/a/34004418/11947314

running a container

interactively

background

log files

remove containers

remove images

docker ps

docker swarm